﻿using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;

namespace TraceView.UI.Entities
{
    public abstract class FilterEntity : BaseEntity
    {
        private bool _isChecked;

        public bool IsChecked
        {
            get { return _isChecked; }
            set { SetProperty(() => IsChecked, ref _isChecked, value); }
        }

        public abstract string KeyValue { get; }
    }

    public interface IFilterCollectionMatchCriteria
    {
        Func<TraceItem, bool> MatchCriteria { get; }
        event FilterChangedDelegate FilterChanged;
    }

    public delegate void FilterChangedDelegate();

    public abstract class FilterEntityCollection<T> : BaseEntityCollection<T>, IFilterCollectionMatchCriteria
        where T : FilterEntity
    {
        public Func<TraceItem, bool> MatchCriteria
        {
            get
            {
                return ti => {
                           if (this.All(item => !item.IsChecked))
                               return true;
                           foreach (T item in this.Where(item => item.IsChecked))
                           {
                               if (TraceItemMatches(item, ti))
                                   return true;
                           }
                           return false;
                       };
            }
        }

        public event FilterChangedDelegate FilterChanged;

        protected abstract bool TraceItemMatches(T item, TraceItem traceItem);

        protected sealed override void InsertItem(int index, T item)
        {
            for (int i = 0; i < Count; i++)
            {
                int compare = string.Compare(this[i].KeyValue, item.KeyValue, StringComparison.OrdinalIgnoreCase);
                if (compare == 0)
                    return;
                if (compare > 0)
                {
                    base.InsertItem(i, item);
                    return;
                }
            }

            base.InsertItem(index, item);
        }

        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            base.OnCollectionChanged(e);
            if (e.NewItems != null)
            {
                foreach (T item in e.NewItems.Cast<T>())
                    item.PropertyChanged += ItemPropertyChanged;
            }
            if (e.OldItems != null)
            {
                foreach (T item in e.OldItems.Cast<T>())
                    item.PropertyChanged -= ItemPropertyChanged;
            }
        }

        private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsChecked")
            {
                if (FilterChanged != null)
                    FilterChanged();
            }
        }
    }
}